﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace HML.Design
{
    /// <summary>
    /// AnomalyButton控件设计模式行为
    /// </summary>
    public class AnomalyButtonDesigner : ControlDesigner
    {
        #region 字段

        /// <summary>
        /// 鼠标左键在路径圆点按下时鼠标的坐标
        /// </summary>
        private PointF mouseLeftDownPoint = PointF.Empty;
        /// <summary>
        /// 鼠标左键在路径圆点按下时圆点的索引
        /// </summary>
        internal int mouseLeftDownObjectIndex = -1;
        /// <summary>
        /// 鼠标左键在路径圆点按下时圆点的坐标
        /// </summary>
        private PointF mouseLeftDownObjectPoint = PointF.Empty;

        /// <summary>
        /// 鼠标右键在路径圆点按下时圆点的索引
        /// </summary>
        private int mouseRightDownObjectIndex = -1;

        /// <summary>
        /// 鼠标进入路径圆点时圆点的索引
        /// </summary>
        internal int mouseEnterObjectIndex = -1;

        /// <summary>
        /// 当前要处理要路径圆点
        /// </summary>
        private PointF[] pointArr = null;

        #endregion

        #region 重写属性

        public DesignerVerbCollection verbs = null;
        /// <summary>
        /// 右键菜单集合
        /// </summary>
        public override DesignerVerbCollection Verbs
        {
            get
            {
                if (this.verbs == null)
                {
                    this.verbs = new DesignerVerbCollection();
                    this.verbs.Add(new DesignerVerb("删除选中编辑点", new EventHandler(this.DeleteSelect)) { Enabled = false });
                    this.verbs.Add(new DesignerVerb("向前面新增编辑点", new EventHandler(this.AddToLeft)) { Enabled = false });
                    this.verbs.Add(new DesignerVerb("向后面新增编辑点", new EventHandler(this.AddToRight)) { Enabled = false });
                }
                if (this.mouseRightDownObjectIndex == -1)
                {
                    for (int i = 0; i < this.verbs.Count; i++)
                    {
                        if (this.verbs[i].Text == "删除选中编辑点" || this.verbs[i].Text == "向前面新增编辑点" || this.verbs[i].Text == "向后面新增编辑点")
                        {
                            this.verbs[i].Enabled = false;
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < this.verbs.Count; i++)
                    {
                        if (this.verbs[i].Text == "删除选中编辑点" || this.verbs[i].Text == "向前面新增编辑点" || this.verbs[i].Text == "向后面新增编辑点")
                        {
                            this.verbs[i].Enabled = true;
                        }
                    }
                }

                return this.verbs;
            }
        }

        #endregion

        #region 扩展

        private const int WM_LBUTTONDOWN = 0x0201; //按下鼠标左键 
        private const int WM_LBUTTONUP = 0x0202; //释放鼠标左键
        private const int WM_RBUTTONDOWN = 0x0204; //按下鼠标右键 
        private const int WM_RBUTTONUP = 0x0205; //释放鼠标右键 
        private const int WM_MOUSEMOVE = 0x0200;//鼠标移动

        #endregion

        public AnomalyButtonDesigner()
        {

        }

        #region 重写

        /// <summary>
        /// 工具箱拖放创建新控件实例
        /// </summary>
        /// <param name="defaultValues"></param>
        public override void InitializeNewComponent(IDictionary defaultValues)
        {
            base.InitializeNewComponent(defaultValues);

            AnomalyButton anomalyButton = (AnomalyButton)this.Component;
            MemberDescriptor member1 = (MemberDescriptor)TypeDescriptor.GetProperties((object)this.Component)["Text"];
            MemberDescriptor member2 = (MemberDescriptor)TypeDescriptor.GetProperties((object)this.Component)["TextLocation"];
            MemberDescriptor member3 = (MemberDescriptor)TypeDescriptor.GetProperties((object)this.Component)["ShapePoints"];
            this.RaiseComponentChanging(member1);
            anomalyButton.Text = "自定义形状";
            this.RaiseComponentChanged(member1, (object)null, (object)null);
            this.RaiseComponentChanging(member2);
            anomalyButton.TextLocation = new PointFR(84, 75);
            this.RaiseComponentChanged(member2, (object)null, (object)null);
            this.RaiseComponentChanging(member3);
            anomalyButton.ShapePoints = "{10.19,22.95} {60.77,58.73} {105.75,22.89} {109.14,58.5} {193.09,8.68} {115.14,100.41} {57.83,101.1}";
            this.RaiseComponentChanged(member3, (object)null, (object)null);
        }

        /// <summary>
        /// 试图设计器初始化控件实例
        /// </summary>
        /// <param name="component"></param>
        public override void Initialize(IComponent component)
        {
            base.Initialize(component);

            AnomalyButton anomalyButton = component as AnomalyButton;
            if (anomalyButton != null)
            {
                anomalyButton.Paint += this.AnomalyButton_Paint;
                anomalyButton.LostFocus += this.AnomalyButton_LostFocus;
            }
        }

        /// <summary>
        /// 当设计器正在管理的控件绘制了它的图面时接收调用，这样设计器就可以在控件顶部绘制任意附加装饰
        /// </summary>
        /// <param name="pe"></param>
        protected override void OnPaintAdornments(PaintEventArgs pe)
        {
            Pen border_pen = new Pen((double)this.Control.BackColor.GetBrightness() < 0.5 ? ControlPaint.Light(this.Control.BackColor) : ControlPaint.Dark(this.Control.BackColor)) { DashStyle = DashStyle.Dash };
            pe.Graphics.DrawRectangle(border_pen, new Rectangle(this.Control.ClientRectangle.X, this.Control.ClientRectangle.Y, this.Control.ClientRectangle.Width - 1, this.Control.ClientRectangle.Height - 1));
            border_pen.Dispose();

            base.OnPaintAdornments(pe);
        }

        /// <summary>
        /// 指示该控件是否应处理在指定点单击鼠标的操作
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        protected override bool GetHitTest(Point point)
        {
            return false;
        }

        /// <summary>
        /// 在每次需要设置光标时接收调用
        /// </summary>
        protected override void OnSetCursor()
        {
            if (Cursor.Current != Cursors.Arrow)
            {
                Cursor.Current = Cursors.Arrow;
            }
        }

        /// <summary>
        /// 处理 Windows 消息，并可以选择将其路由到控件。
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_LBUTTONDOWN)
            {
                this.MouseLeftDown();
            }
            else if (m.Msg == WM_LBUTTONUP)
            {
                this.MouseLeftUp();
            }
            else if (m.Msg == WM_RBUTTONDOWN)
            {
                this.MouseRightDown();
            }
            else if (m.Msg == WM_RBUTTONUP)
            {
                this.MouseRightUp();
            }
            else if (m.Msg == WM_MOUSEMOVE)
            {
                this.MouseMove();
                if (this.mouseLeftDownObjectIndex > -1)
                {
                    return;
                }
            }

            base.WndProc(ref m);
        }

        #endregion

        #region  私有方法

        /// <summary>
        /// 绘制编辑模式下路劲和圆点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AnomalyButton_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            AnomalyButton anomalyButton = (AnomalyButton)sender;

            PointF[] pointsArr = AnomalyButton.UnScaleStrConvertToScaleArr(anomalyButton.ShapePoints, anomalyButton.ScaleDpi);

            //绘制路径
            if (anomalyButton.ShapeEditorEnabled == true && pointsArr.Length >= 3)
            {
                Pen shapePath_pan = new Pen(anomalyButton.ShapePathLineColor);
                if (anomalyButton.StylePattern == AnomalyButtonStylePattern.Bezier)
                {
                    g.DrawClosedCurve(shapePath_pan, pointsArr);
                }
                else
                {
                    g.DrawPolygon(shapePath_pan, pointsArr);
                }
                shapePath_pan.Dispose();
            }

            // 绘制路径坐标
            if (anomalyButton.ShapeEditorEnabled == true)
            {
                SolidBrush shapePoint_normal_sb = null;
                SolidBrush shapePoint_enter_sb = null;
                SolidBrush shapePoint_text_sb = null;
                Font shapePoint_font = null;
                int scale_shapePathPointRadius = (int)(anomalyButton.ShapePathPointRadius * anomalyButton.ScaleDpi);
                for (int i = 0; i < pointsArr.Length; i++)
                {
                    RectangleF rect_tmp = new RectangleF(pointsArr[i].X - scale_shapePathPointRadius, pointsArr[i].Y - scale_shapePathPointRadius, scale_shapePathPointRadius * 2, scale_shapePathPointRadius * 2);
                    if (this.mouseLeftDownObjectIndex == i || this.mouseEnterObjectIndex == i)
                    {
                        if (shapePoint_enter_sb == null)
                        {
                            shapePoint_enter_sb = new SolidBrush(anomalyButton.ShapePathPointEnterColor);
                        }
                        g.FillEllipse(shapePoint_enter_sb, rect_tmp);
                    }
                    else
                    {
                        if (shapePoint_normal_sb == null)
                        {
                            shapePoint_normal_sb = new SolidBrush(anomalyButton.ShapePathPointNormalColor);
                        }
                        g.FillEllipse(shapePoint_normal_sb, rect_tmp);
                    }

                    if (anomalyButton.ShapePathPointTipEnable)
                    {
                        if (shapePoint_text_sb == null)
                        {
                            shapePoint_text_sb = new SolidBrush(anomalyButton.ShapePathPointTipColor);
                        }
                        if (shapePoint_font == null)
                        {
                            shapePoint_font = (Font)Control.DefaultFont.Clone();
                        }
                        SizeF tip_size = g.MeasureString(i.ToString(), shapePoint_font);
                        int y = (int)((rect_tmp.Y > tip_size.Height) ? rect_tmp.Y - tip_size.Height : rect_tmp.Bottom + 4);
                        g.DrawString(i.ToString(), shapePoint_font, shapePoint_text_sb, new PointF(rect_tmp.X, y));
                    }
                }

                if (shapePoint_normal_sb != null)
                    shapePoint_normal_sb.Dispose();
                if (shapePoint_enter_sb != null)
                    shapePoint_enter_sb.Dispose();
                if (shapePoint_text_sb != null)
                    shapePoint_text_sb.Dispose();
                if (shapePoint_font != null)
                    shapePoint_font.Dispose();
            }

        }
        /// <summary>
        /// 控件失去焦点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AnomalyButton_LostFocus(object sender, EventArgs e)
        {
            AnomalyButton ab = (AnomalyButton)this.Control;

            if (this.mouseLeftDownObjectIndex != -1)
            {
                this.mouseLeftDownPoint = PointF.Empty;
                this.mouseLeftDownObjectIndex = -1;
                this.mouseLeftDownObjectPoint = PointF.Empty;
                ab.Invalidate();
            }
        }

        /// <summary>
        /// 鼠标在控件可视区域按下左键
        /// </summary>
        protected void MouseLeftDown()
        {
            AnomalyButton ab = (AnomalyButton)this.Control;

            Point point = ab.PointToClient(Control.MousePosition);
            if ((bool)(TypeDescriptor.GetProperties(ab)["Locked"]).GetValue(ab) || !ab.ShapeEditorEnabled)
            {
                return;
            }

            this.pointArr = AnomalyButton.UnScaleStrConvertToScaleArr(ab.ShapePoints, ab.ScaleDpi);

            int scale_shapePathPointRadius = (int)(ab.ShapePathPointRadius * ab.ScaleDpi);
            int index = -1;
            for (int i = 0; i < this.pointArr.Length; i++)
            {
                PointF item = this.pointArr[i];
                if (item.X - scale_shapePathPointRadius < point.X && item.Y - scale_shapePathPointRadius < point.Y && point.X < item.X + scale_shapePathPointRadius && point.Y < item.Y + scale_shapePathPointRadius)
                {
                    index = i;
                    break;
                }
            }

            this.mouseLeftDownPoint = point;
            this.mouseLeftDownObjectIndex = index;
            this.mouseLeftDownObjectPoint = (index == -1) ? Point.Empty : this.pointArr[this.mouseLeftDownObjectIndex];

            this.mouseRightDownObjectIndex = -1;
            if (this.verbs != null)
            {
                for (int i = 0; i < this.verbs.Count; i++)
                {
                    if (this.verbs[i].Text == "删除选中编辑点" || this.verbs[i].Text == "向前面新增编辑点" || this.verbs[i].Text == "向后面新增编辑点")
                    {
                        this.verbs[i].Enabled = false;
                    }
                }
            }

            ab.Invalidate();
        }
        /// <summary>
        /// 鼠标在控件可视区域按下右键
        /// </summary>
        protected void MouseRightDown()
        {
            this.mouseLeftDownPoint = Point.Empty;
            this.mouseLeftDownObjectIndex = -1;
            this.mouseLeftDownObjectPoint = Point.Empty;

            AnomalyButton ab = (AnomalyButton)this.Control;

            Point point = ab.PointToClient(Control.MousePosition);
            if ((bool)(TypeDescriptor.GetProperties(ab)["Locked"]).GetValue(ab) || !ab.ShapeEditorEnabled)
            {
                return;
            }

            this.pointArr = AnomalyButton.UnScaleStrConvertToScaleArr(ab.ShapePoints, ab.ScaleDpi);

            int scale_shapePathPointRadius = (int)(ab.ShapePathPointRadius * ab.ScaleDpi);
            int index = -1;
            for (int i = 0; i < this.pointArr.Length; i++)
            {
                PointF item = this.pointArr[i];
                if (item.X - scale_shapePathPointRadius < point.X && item.Y - scale_shapePathPointRadius < point.Y && point.X < item.X + scale_shapePathPointRadius && point.Y < item.Y + scale_shapePathPointRadius)
                {
                    index = i;
                    break;
                }
            }

            this.mouseRightDownObjectIndex = index;
        }
        /// <summary>
        /// 鼠标在控件可视区域按下左键后释放
        /// </summary>
        protected void MouseLeftUp()
        {
            if (this.mouseLeftDownObjectIndex != -1)
            {
                this.mouseLeftDownPoint = Point.Empty;
                this.mouseLeftDownObjectIndex = -1;
                this.mouseLeftDownObjectPoint = PointF.Empty;
                this.Control.Invalidate();
            }
        }
        /// <summary>
        /// 鼠标在控件可视区域按下右键后释放
        /// </summary>
        protected void MouseRightUp()
        {
            bool isenabled = !(this.mouseRightDownObjectIndex == -1);

            if (this.verbs != null)
            {
                for (int i = 0; i < this.verbs.Count; i++)
                {
                    if (this.verbs[i].Text == "删除选中编辑点" || this.verbs[i].Text == "向前面新增编辑点" || this.verbs[i].Text == "向后面新增编辑点")
                    {
                        this.verbs[i].Enabled = isenabled;
                    }
                }
            }
        }
        /// <summary>
        /// 鼠标移动
        /// </summary>
        protected void MouseMove()
        {
            AnomalyButton ab = (AnomalyButton)this.Control;

            Point point = ab.PointToClient(Control.MousePosition);
            if ((bool)(TypeDescriptor.GetProperties(ab)["Locked"]).GetValue(ab) || !ab.ShapeEditorEnabled)
            {
                return;
            }

            //鼠标移动某一个点
            if (this.mouseLeftDownObjectIndex > -1)
            {
                float offset_x = point.X - this.mouseLeftDownPoint.X;
                float offset_y = point.Y - this.mouseLeftDownPoint.Y;
                if (offset_x != 0 || offset_y != 0)
                {
                    this.pointArr[this.mouseLeftDownObjectIndex] = new PointF(this.mouseLeftDownObjectPoint.X + offset_x, this.mouseLeftDownObjectPoint.Y + offset_y);

                    (TypeDescriptor.GetProperties(ab)["ShapePoints"]).SetValue(ab, AnomalyButton.ScaleArrConvertToUnScaleStr(this.pointArr, ab.ScaleDpi));
                }
            }
            else
            {
                if (this.pointArr == null)
                {
                    this.pointArr = AnomalyButton.UnScaleStrConvertToScaleArr(ab.ShapePoints, ab.ScaleDpi);
                }

                int scale_shapePathPointRadius = (int)(ab.ShapePathPointRadius * ab.ScaleDpi);
                int index = -1;
                for (int i = 0; i < this.pointArr.Length; i++)
                {
                    PointF item = this.pointArr[i];
                    if (item.X - scale_shapePathPointRadius < point.X && item.Y - scale_shapePathPointRadius < point.Y && point.X < item.X + scale_shapePathPointRadius && point.Y < item.Y + scale_shapePathPointRadius)
                    {
                        index = i;
                        break;
                    }
                }
                if (this.mouseEnterObjectIndex != index)
                {
                    this.mouseEnterObjectIndex = index;
                    this.Control.Invalidate();
                }
            }
        }

        /// <summary>
        /// 右键菜单删除选中路径点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DeleteSelect(object sender, EventArgs e)
        {
            AnomalyButton ab = (AnomalyButton)this.Control;
            PointF[] pointArr_old = AnomalyButton.UnScaleStrConvertToUnScaleArr(ab.ShapePoints);
            PointF[] pointArr_new = new PointF[pointArr_old.Length - 1];

            if (pointArr_old.Length > 1)
            {
                for (int i = 0; i < pointArr_old.Length; i++)
                {
                    if (i != this.mouseRightDownObjectIndex)
                    {
                        pointArr_new[(i < this.mouseRightDownObjectIndex) ? i : i - 1] = pointArr_old[i];
                    }
                }
            }

            (TypeDescriptor.GetProperties(ab)["ShapePoints"]).SetValue(ab, AnomalyButton.UnScaleArrConvertToUnScaleStr(pointArr_new));
            this.mouseRightDownObjectIndex = -1;
            this.pointArr = null;
            this.mouseEnterObjectIndex = -1;
        }
        /// <summary>
        /// 右键菜单新增一个点到选中的路径点的左边
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AddToLeft(object sender, EventArgs e)
        {
            AnomalyButton ab = (AnomalyButton)this.Control;
            PointF[] pointArr_old = AnomalyButton.UnScaleStrConvertToUnScaleArr(ab.ShapePoints);
            PointF[] pointArr_new = new PointF[pointArr_old.Length + 1];

            for (int i = 0; i < pointArr_old.Length; i++)
            {
                if (i < this.mouseRightDownObjectIndex)
                {
                    pointArr_new[i] = pointArr_old[i];
                }
                else if (i == this.mouseRightDownObjectIndex)
                {
                    float x = 0;
                    float y = 0;
                    if (i == 0)
                    {
                        x = pointArr_old[i].X + (pointArr_old[pointArr_old.Length - 1].X - pointArr_old[i].X) / 2;
                        y = pointArr_old[i].Y + (pointArr_old[pointArr_old.Length - 1].Y - pointArr_old[i].Y) / 2;
                    }
                    else if (pointArr_old.Length < 2)
                    {
                        x = pointArr_old[i].X - ab.ShapePathPointRadius * 3;
                        y = pointArr_old[i].Y;
                    }
                    else if (i > 0)
                    {
                        x = pointArr_old[i].X - (pointArr_old[i].X - pointArr_old[i - 1].X) / 2;
                        y = pointArr_old[i].Y - (pointArr_old[i].Y - pointArr_old[i - 1].Y) / 2;
                    }
                    pointArr_new[i] = new PointF(x, y);
                    pointArr_new[i + 1] = pointArr_old[i];
                }
                else
                {
                    pointArr_new[i + 1] = pointArr_old[i];
                }
            }

            (TypeDescriptor.GetProperties(ab)["ShapePoints"]).SetValue(ab, AnomalyButton.UnScaleArrConvertToUnScaleStr(pointArr_new));
            this.mouseRightDownObjectIndex = -1;
            this.pointArr = null;
            this.mouseEnterObjectIndex = -1;
        }
        /// <summary>
        /// 右键菜单新增一个点到选中的路径点的右边
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AddToRight(object sender, EventArgs e)
        {
            AnomalyButton ab = (AnomalyButton)this.Control;
            PointF[] pointArr_old = AnomalyButton.UnScaleStrConvertToUnScaleArr(ab.ShapePoints);
            PointF[] pointArr_new = new PointF[pointArr_old.Length + 1];

            for (int i = 0; i < pointArr_old.Length; i++)
            {
                if (i < this.mouseRightDownObjectIndex)
                {
                    pointArr_new[i] = pointArr_old[i];
                }
                else if (i == this.mouseRightDownObjectIndex)
                {
                    float x = 0;
                    float y = 0;
                    if (pointArr_old.Length < 2)
                    {
                        x = pointArr_old[i].X + ab.ShapePathPointRadius * 3;
                        y = pointArr_old[i].Y;
                    }
                    else if (i < pointArr_old.Length - 1)
                    {
                        x = pointArr_old[i].X + (pointArr_old[i + 1].X - pointArr_old[i].X) / 2;
                        y = pointArr_old[i].Y + (pointArr_old[i + 1].Y - pointArr_old[i].Y) / 2;
                    }
                    else if (i == pointArr_old.Length - 1)
                    {
                        x = pointArr_old[i].X - (pointArr_old[i].X - pointArr_old[0].X) / 2;
                        y = pointArr_old[i].Y - (pointArr_old[i].Y - pointArr_old[0].Y) / 2;
                    }
                    pointArr_new[i] = pointArr_old[i];
                    pointArr_new[i + 1] = new PointF(x, y);
                }
                else
                {
                    pointArr_new[i + 1] = pointArr_old[i];
                }
            }

          (TypeDescriptor.GetProperties(ab)["ShapePoints"]).SetValue(ab, AnomalyButton.UnScaleArrConvertToUnScaleStr(pointArr_new));
            this.mouseRightDownObjectIndex = -1;
            this.pointArr = null;
            this.mouseEnterObjectIndex = -1;
        }

        #endregion
    }

}
